package indi.zhifa.recipe.bailan.framework.auth.service.impl;
import indi.zhifa.recipe.bailan.framework.auth.dao.IBaseAuthNodeRelevantDao;
import indi.zhifa.recipe.bailan.framework.auth.dao.IBaseUserRelevantDao;
import indi.zhifa.recipe.bailan.framework.auth.entity.BaseTokenObject;
import indi.zhifa.recipe.bailan.framework.auth.entity.dto.TokenAuthNodeDto;
import indi.zhifa.recipe.bailan.framework.auth.entity.dto.user.LoginDto;
import indi.zhifa.recipe.bailan.framework.auth.entity.exception.AuthException;
import indi.zhifa.recipe.bailan.framework.auth.entity.po.BaseRelUserAuthEntity;
import indi.zhifa.recipe.bailan.framework.auth.entity.po.BaseRelUserRoleEntity;
import indi.zhifa.recipe.bailan.framework.auth.entity.po.BaseUserEntity;
import indi.zhifa.recipe.bailan.framework.auth.entity.vo.BaseLoginInfoVo;
import indi.zhifa.recipe.bailan.framework.auth.service.IBaseLoginService;
import indi.zhifa.recipe.bailan.framework.auth.util.IBaseTokenUtil;
import indi.zhifa.recipe.bailan.framework.common.entity.exception.ServiceException;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RequiredArgsConstructor
public abstract class BaseLoginServiceImpl implements IBaseLoginService {

    protected final IBaseUserRelevantDao mUserRelevantDao;
    protected final IBaseAuthNodeRelevantDao mDepartmentRelevantDao;
    protected final PasswordEncoder mPasswordEncoder;

    protected final IBaseTokenUtil mBaseTokenUtil;

    @Override
    public BaseLoginInfoVo login(LoginDto pLoginDto) {
        // 对比密码
        BaseUserEntity userEntity = mUserRelevantDao.user_check(pLoginDto.getUserName());
        if(userEntity.getBan()){
            throw new AuthException("账号"+userEntity.getName()+"已被禁用，请联系管理员");
        }

        String sourceEncodedPasswd = userEntity.getPassword();
        if(!mPasswordEncoder.matches(pLoginDto.getPasswd(),sourceEncodedPasswd)){
            throw new ServiceException("密码不正确");
        }
        // 创建BaseTokenObject
        BaseTokenObject baseTokenObject = mBaseTokenUtil.createTokenObject();
        // 填充用户相关信息
        baseTokenObject.setId(userEntity.getId());
        baseTokenObject.setName(userEntity.getName());
        baseTokenObject.setPasswdExpireTime(userEntity.getExpireTime());
        fillOtherInfo(baseTokenObject,userEntity);
        // 填充角色相关信息
        List<String> roles = getUserRoles(userEntity.getId());
        baseTokenObject.setRoles(roles);
        // 填充部门相关
        List<BaseRelUserAuthEntity> baseRelUserRoleEntityList = mDepartmentRelevantDao.relUserAuth_listByUserId(userEntity.getId());
        Map<String, TokenAuthNodeDto> depInfo = baseRelUserRoleEntityList.stream().collect(Collectors.toMap(
                BaseRelUserAuthEntity::getDomainCode, baseRelUserDepEntity->{
                    TokenAuthNodeDto tokenAuthNodeDto = new TokenAuthNodeDto();
                    tokenAuthNodeDto.setAuthId(baseRelUserDepEntity.getAuthId());
                    tokenAuthNodeDto.setAuthCode(baseRelUserDepEntity.getAuthCode());
                    tokenAuthNodeDto.setAuthCascade(baseRelUserDepEntity.getAuthCascade());
                    return tokenAuthNodeDto;
                }));
        baseTokenObject.setAuthNodeInfo(depInfo);

        // 产生token串
        String tokenStr = mBaseTokenUtil.generateToken(baseTokenObject);
        // 返回BaseLoginInfoVo
        BaseLoginInfoVo baseLoginInfoVo = new BaseLoginInfoVo();
        baseLoginInfoVo.setUserEntity(userEntity);
        baseLoginInfoVo.setRoles(roles);
        baseLoginInfoVo.setToken(tokenStr);
        baseLoginInfoVo.setDepartmentInfo(depInfo);
        return baseLoginInfoVo;
    }

    protected abstract BaseTokenObject fillOtherInfo(BaseTokenObject pBaseTokenObject,BaseUserEntity pBaseUserEntity);

    protected List<String> getUserRoles(Long pUserId){
        List<BaseRelUserRoleEntity> relUserRoleEntityList = mUserRelevantDao.relUserRole_listByUserId(pUserId);
        List<String> roles = relUserRoleEntityList.stream().map(BaseRelUserRoleEntity::getRoleCode).collect(Collectors.toList());
        return roles;
    }
}
